{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python decorators\n",
    "\n",
    "Josh Montague, 2015-12\n",
    "\n",
    "*Built on OS X, with IPython 3.0 on Python 2.7*\n",
    "\n",
    "In this session, we'll dig into some details of Python functions. The end goal will be to understand how and why you might want to create decorators with Python functions.\n",
    "\n",
    ">*Note:* there is an Appendix at the end of this notebook that dives deeper into scope and Python namespaces. I wrote out the content because they're quite relevant to talking about decorators. But, ultimately, we only 45 minutes, and it couldn't all fit. If you're curious, take a few extra minutes to review that material, as well. \n",
    "\n",
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Functions\n",
    "\n",
    "A lot of this RST has to do with understanding the subtleties of Python functions. So, we're going to spend some time exploring them.\n",
    "\n",
    "**In Python, functions are objects**\n",
    "\n",
    "> [T]his means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures. ([wiki](https://en.wikipedia.org/wiki/First-class_function))\n",
    "\n",
    "This is not true (or at least not easy) in all programming languages. I don't have a ton of experience to back this up. But, many moons ago, I remember that Java functions only lived inside objects and classes. \n",
    "\n",
    "Let's take a moment to **look at a relatively simple function and appreciate what it does** and what we can do with it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def duplicator(str_arg):\n",
    "    \"\"\"Create a string that is a doubling of the passed-in arg.\"\"\" \n",
    "    # use the passed arg to create a larger string (double it, with a space between)\n",
    "    internal_variable = ' '.join( [str_arg, str_arg] )\n",
    "    \n",
    "    return internal_variable"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<function duplicator at 0x103c330c8>\n"
     ]
    }
   ],
   "source": [
    "# print (don't call) the function \n",
    "print( duplicator )\n",
    "\n",
    "# equivalently (in IPython):\n",
    "#duplicator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remember that IPython and Jupyter will automatically (and conveniently!) call the ``__repr__`` of an object if it is the last thing in the cell. But I'll use the ``print()`` function explicitly just to be clear. \n",
    "\n",
    "This  displays the string representation of the object. It usually includes: \n",
    "\n",
    "- an object type (class)\n",
    "- an object name\n",
    "- a memory location\n",
    "\n",
    "Now, let's actually call the function (which we do with use of the parentheses), and assign the return value (a string) to a new variable. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# now *call* the function by using parens\n",
    "output = duplicator('yo')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "yo yo\n"
     ]
    }
   ],
   "source": [
    "# verify the expected behavior\n",
    "print(output)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Because functions are objects, **they have attributes** just like any other Python object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__call__',\n",
       " '__class__',\n",
       " '__closure__',\n",
       " '__code__',\n",
       " '__defaults__',\n",
       " '__delattr__',\n",
       " '__dict__',\n",
       " '__doc__',\n",
       " '__format__',\n",
       " '__get__',\n",
       " '__getattribute__',\n",
       " '__globals__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__module__',\n",
       " '__name__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " 'func_closure',\n",
       " 'func_code',\n",
       " 'func_defaults',\n",
       " 'func_dict',\n",
       " 'func_doc',\n",
       " 'func_globals',\n",
       " 'func_name']"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# the dir() built-in function displays the argument's attributes\n",
    "dir(duplicator)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Because functions are objects, **we can pass them around** like any other data type. For example, **we can assign them to other variables**! If you occasionally still have dreams about the Enumerator, this will look familiar."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'ring ring'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# first, recall the normal behavior of useful_function() \n",
    "duplicator('ring')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# now create a new variable and assign our function to it\n",
    "another_duplicator = duplicator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'giggity giggity'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# now, we can use the *call* notation because the new variable is \n",
    "#  assigned the original function\n",
    "another_duplicator('giggity')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "original function: <function duplicator at 0x103c330c8>\n",
      "\n",
      "new function: <function duplicator at 0x103c330c8>\n"
     ]
    }
   ],
   "source": [
    "# and we can verify that this is actually a reference to the \n",
    "#  original function\n",
    "print( \"original function: %s\" % duplicator )\n",
    "print\n",
    "print( \"new function: %s\" % another_duplicator )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By looking at the memory location, we can see that the second function is just a pointer to the first function! Cool!\n",
    "\n",
    "\n",
    "## Functions inside functions\n",
    "\n",
    "With an understanding of what's inside a function and what we can do with it, **consider the case were we define a new function *within* another function.** \n",
    "\n",
    "*This may seem overly complicated for a little while, but stick with me.*\n",
    "\n",
    "\n",
    "In the example below, we'll define an outer function which includes a local variable, then a local function definition. The inner function returns a string. The outer function calls the inner function, and returns the resulting value (a string)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def speaker():\n",
    "    \"\"\"\n",
    "    Simply return a word (a string).\n",
    "    \n",
    "    Other than possibly asking 'why are you writing this simple \n",
    "    function in such a complicated fashion?' this should \n",
    "    hopefuly should be pretty clear.\n",
    "    \"\"\"\n",
    "    \n",
    "    # define a local variable\n",
    "    word='hello'\n",
    "    \n",
    "    def shout():\n",
    "        \"\"\"Return a capitalized version of word.\"\"\"\n",
    "        \n",
    "        # though not in the innermost scope, this is in the namespace one \n",
    "        #  level out from here\n",
    "        return word.upper()\n",
    "    \n",
    "    # call shout and then return the result of calling it (a string)\n",
    "    return shout()        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "HELLO\n"
     ]
    }
   ],
   "source": [
    "# remember that the result is a string, now print it. the sequence:\n",
    "# - put word and shout in local namespace\n",
    "# - define shout()\n",
    "# - call shout()\n",
    "# - look for 'word', return it\n",
    "# - return the return value of shout()\n",
    "print( speaker() )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, this may be intuitive, but it's important to note that the inner function is *not* accessible outside of the outer function. The interpreter can always step out into larger (or \"more outer\") namespaces, but we can't dig deeper into smaller ones."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name 'shout' is not defined\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    # this function only exists in the local scope of the outer function\n",
    "    shout()\n",
    "except NameError, e:\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Functions out of functions\n",
    "\n",
    "What if we'd like our outer function to **return a function**? For example, return the inner function instead of the *return value* of the inner function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def speaker_func():\n",
    "    \"\"\"Similar to speaker(), but this time return the actual inner function!\"\"\"\n",
    "    \n",
    "    word = 'hello'\n",
    "    \n",
    "    def shout():\n",
    "        \"\"\"Return an all-caps version of the passed word.\"\"\"\n",
    "        return word.upper()\n",
    "    \n",
    "    # don't *call* shout(), just return it\n",
    "    return shout"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<function shout at 0x103c33320>\n"
     ]
    }
   ],
   "source": [
    "# remember: our function returns another function \n",
    "print( speaker_func() )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remember that the return value of the outer function is another function. And just like we saw earlier, we can ``print`` the function to see the name and memory location.\n",
    "\n",
    "Note that the name is that of the inner function. Makes sense, since that's what we returned.\n",
    "\n",
    "Like we said before, since this is an object, **we can pass this function around and assign it to other variables**. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# this will assign to the variable new_shout, a value that is the shout function\n",
    "new_shout = speaker_func()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Which means **we can also call it** with parens, as usual."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'HELLO'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# which means we can *call* it\n",
    "new_shout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Functions into functions\n",
    "\n",
    "If functions are objects, **we can just as easily pass a function *into* another function.** You've probably seen this before in the context of sorting, or maybe using ``map``:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(9, 2), (5, 4), (1, 5)]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from operator import itemgetter\n",
    "\n",
    "# we might want to sort this by the first or second item\n",
    "tuple_list = [(1,5),(9,2),(5,4)]\n",
    "\n",
    "# itemgetter is a callable (like a function) that we pass in as an argument to sorted()\n",
    "sorted(tuple_list, key=itemgetter(1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[6, 11, 9]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def tuple_add(tup):\n",
    "    \"\"\"Sum the items in a tuple.\"\"\"\n",
    "    return sum(tup)\n",
    "\n",
    "# now we can map the tuple_add() function across the tuple_list iterable.\n",
    "#  note that we're passing a function as an argument!\n",
    "map(tuple_add, tuple_list)    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we can pass functions into and out of other functions, then I propose that **we can *extend* or *modify the behavior of* a function without actually editing the original function!**\n",
    "\n",
    "\n",
    "## Decorators \n",
    "\n",
    "🎉💥🎉💥🎉💥🎉💥🎉💥\n",
    "\n",
    "For example, say there's some previously-defined function in and you'd like it to be more verbose. For now, let's just assume that printing a bunch of information to stdout is our goal. \n",
    "\n",
    "Below, we define a function ``verbose()`` that takes another function as an argument. It does other tasks both before and after actually calling the passed-in function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def verbose(func):\n",
    "    \"\"\"Add some marginally annoying verbosity to the passed func.\"\"\"\n",
    "    \n",
    "    def inner():\n",
    "        print(\"heeeeey everyone, I'm about to do a thing!\")\n",
    "        print(\"hey hey hey, I'm about to call a function called: {}\".format(func.__name__))\n",
    "        print\n",
    "        # now call (and print) the passed function\n",
    "        print func()\n",
    "        print\n",
    "        print(\"whoa, did everyone see that thing I just did?! SICK!!\")\n",
    "        \n",
    "    return inner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, imagine we have a function that we wish had more of this type of \"logging.\" But, we don't want to jump in and add a bunch of code to the original function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# here's our original function (that we don't want to modify) \n",
    "def say_hi():\n",
    "    \"\"\"Return 'hi'.\"\"\"\n",
    "    return '--> hi. <--'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'--> hi. <--'"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# understand the original behavior of the function\n",
    "say_hi()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Instead, we pass the original function as an arg to our ``verbose`` function. Remember that this returns the inner function, so we can assign it and then call it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# this is now a function...\n",
    "verbose_say_hi = verbose(say_hi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "heeeeey everyone, I'm about to do a thing!\n",
      "hey hey hey, I'm about to call a function called: say_hi\n",
      "\n",
      "--> hi. <--\n",
      "\n",
      "whoa, did everyone see that thing I just did?! SICK!!\n"
     ]
    }
   ],
   "source": [
    "# which we can call...\n",
    "verbose_say_hi()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Looking at the output, we can see that when we called ``verbose_say_hi()``, all of the code in it ran:\n",
    "\n",
    "- two print statements\n",
    "- then the passed function ``say_hi()`` was called \n",
    "- it's return value was printed \n",
    "- finally, there was some other printing defined in the inner function\n",
    "\n",
    "We'd now say that **``verbose_say_hi()`` is a *decorated version* of ``say_hi()``.** And, correspondingly, **that ``verbose()`` is our decorator.**\n",
    "\n",
    ">A decorator is a callable that takes a function as an argument and returns a function (probably a modified version of the original function).\n",
    "\n",
    "\n",
    "Now, you may also decide that the modified version of the function is *the only* version you want around. And, further, you don't want to change any other code that may depend on this. In that case, **you want to overwrite the namespace value for the original function**!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "heeeeey everyone, I'm about to do a thing!\n",
      "hey hey hey, I'm about to call a function called: say_hi\n",
      "\n",
      "--> hi. <--\n",
      "\n",
      "whoa, did everyone see that thing I just did?! SICK!!\n"
     ]
    }
   ],
   "source": [
    "# this will clobber the existing namespace value (the original function def). \n",
    "# in it's place we have the verbose version!\n",
    "say_hi = verbose(say_hi)\n",
    "\n",
    "say_hi()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Uneditable source code\n",
    "\n",
    "One use-case where this technique can be useful is when you need to use an existing base of code that you can't edit. There's an existing library that defines classes and methods that are aligned with your needs, but you need a slight variation on them.\n",
    "\n",
    "Imagine there is a library called (creatively) ``uneditable_lib`` that implements a ``Coordinate`` class (a point in two-dimensional space), and an ``add()`` method. The ``add()`` method allows you to add the vectors of two ``Coordinates`` together and returns a new ``Coordinate`` object. It has great documentation and you know the source Python source code looks like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#!/usr/bin/env python\r\n",
      "# -*- coding: UTF-8 -*-\r\n",
      "\r\n",
      "\"\"\"\r\n",
      "A simple module representing a Coordinate class and related method. \r\n",
      "\r\n",
      "Modified from Simeon Franklin's blog:\r\n",
      "- http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/ \r\n",
      "\"\"\"\r\n",
      "\r\n",
      "class Coordinate(object):\r\n",
      "    \"\"\"Represents a point in two-dimensional space.\"\"\"\r\n",
      "    def __init__(self, x, y):\r\n",
      "        self.x = x\r\n",
      "        self.y = y\r\n",
      "\r\n",
      "    def __repr__(self):\r\n",
      "        return \"Coord: \" + str(self.__dict__)\r\n",
      "\r\n",
      "def add(a, b):\r\n",
      "    \"\"\"Combine two Coordinates by addition.\"\"\"\r\n",
      "    return Coordinate(a.x + b.x, a.y + b.y)\r\n",
      "\r\n"
     ]
    }
   ],
   "source": [
    "! cat _uneditable_lib.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# BUT\n",
    "\n",
    "Imagine you don't actually have the Python source, you have the compiled binary. Try opening this file in vi and see how it looks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "uneditable_lib.pyc\r\n"
     ]
    }
   ],
   "source": [
    "! ls | grep .pyc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# you can still *use* the compiled code\n",
    "from uneditable_lib import Coordinate, add"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Coord: {'y': 200, 'x': 100}\n"
     ]
    }
   ],
   "source": [
    "# make a couple of coordinates using the existing library\n",
    "coord_1 = Coordinate(x=100, y=200)\n",
    "coord_2 = Coordinate(x=-500, y=400)\n",
    "\n",
    "print( coord_1 )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Coord: {'y': 600, 'x': -400}\n"
     ]
    }
   ],
   "source": [
    "print( add(coord_1, coord_2) )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But, imagine that **for our particular use-case, we need to confine the resulting coordinates to the first quadrant** (that is, ``x > 0`` and ``y > 0``). We want any negative component in the coordinates to just be truncated to zero.\n",
    "\n",
    "We can't edit the source code, but we can decorate (and modify) it!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def coordinate_decorator(func):                                                                        \n",
    "    \"\"\"Decorates the pre-built source code for Coordinates.\n",
    "    \n",
    "    We need the resulting coordinates to only exist in the \n",
    "    first quadrant, so we'll truncate negative values to zero.\n",
    "    \"\"\"\n",
    "    def checker(a, b): \n",
    "        \"\"\"Enforces first-quadrant coordinates.\"\"\"\n",
    "        ret = func(a, b)\n",
    "        \n",
    "        # check the result and make sure we're still in the \n",
    "        #  first quadrant at the end [ that is, x and y > 0 ]\n",
    "        if ret.x < 0 or ret.y < 0:\n",
    "            ret = Coordinate(ret.x if ret.x > 0 else 0, \n",
    "                             ret.y if ret.y > 0 else 0\n",
    "                            )        \n",
    "        return ret\n",
    "    \n",
    "    return checker"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can decorate the preexisting ``add()`` function with our new wrapper. And since we may be using other code from ``uneditable_lib`` with an API that expects the function to still be called ``add()``, we can just overwrite that namespace variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# first we decorate the existing function\n",
    "add = coordinate_decorator(add)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Coord: {'y': 600, 'x': 0}\n"
     ]
    }
   ],
   "source": [
    "# then we can call it as before\n",
    "print( add(coord_1, coord_2) )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And, we now have a truncated ``Coordinate`` that lives in the first quadrant."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<img src=\"http://i.giphy.com/8VrtCswiLDNnO.gif\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import Image\n",
    "Image(url='http://i.giphy.com/8VrtCswiLDNnO.gif')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we are running out of time, this is an ok place to wrap up.\n",
    "\n",
    "## Examples \n",
    "\n",
    "Here are some real examples you might run across in the wild:\n",
    "\n",
    "- Flask (web framework) uses decorators really well\n",
    "    - [``@app.route``](http://flask.pocoo.org/docs/0.10/api/#flask.Flask.add_url_rule) is a decorator that lets you decorate an arbitrary Python function and turn it into a URL path.\n",
    "    - [``@login_required``](http://flask.pocoo.org/docs/0.10/patterns/viewdecorators/#login-required-decorator) is a decorator that lets your function define the appropriate authentication.\n",
    "- Fabric (ops / remote server tasks) [includes a number of \"helper decorators\"](http://docs.fabfile.org/en/1.10/api/core/decorators.html) for task and hostname management.\n",
    "\n",
    "\n",
    "## Here are some things we didn't cover\n",
    "\n",
    "If you go home tonight and can't possibly wait to learn more about decorators, here are the next things to look up:\n",
    "\n",
    "- passing arguments to a decorator \n",
    "- ``@functools.wraps``\n",
    "- implementing a decorator as a class\n",
    "\n",
    "If there is sufficient interest in a **Decorators, Part Deux,** those would be good starters.\n",
    "\n",
    "\n",
    "# THE END\n",
    "\n",
    "----\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Is there still time?!\n",
    "\n",
    "If so, here are a couple of other useful things worth saying, quickly...\n",
    "\n",
    "\n",
    "## Decorating a function at definition (with ``@``)\n",
    "\n",
    "You might still want to use a decorator to **modify a function that you wrote in your own code.**\n",
    "\n",
    "You might ask *\"But if we're already writing the code, why not just make the function do what we want in the first place?\"* Valid question. \n",
    "\n",
    "One place where this comes up is in practicing [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) (Don't Repeat Yourself) software engineering practices. **If an identical block of logic is to be used in many places, that code should ideally be written in only one place.** \n",
    "\n",
    "In our case, we could imagine making a bunch of different functions more verbose. Instead of adding the verbosity (print statements) to each of the functions, we should define that once and then decorate the other functions.\n",
    "\n",
    "Another nice example is making your code easier to understand by **separating necessary operational logic from the business logic.**\n",
    "\n",
    "There's a nice shorthand - some syntactic sugar - for this kind of statement. To illustrate it, let's just use a variation on a method from earlier. First, see how the original function behaves:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'--> bye. <--'"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def say_bye():\n",
    "    \"\"\"Return 'bye'.\"\"\"\n",
    "    return '--> bye. <--'\n",
    "\n",
    "say_bye()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remember the ``verbose()`` decorator that we already created? If this function (and perhaps others) should be made verbose at the time they're defined, we can apply the decorator right then and there using the ``@`` shorthand:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "heeeeey everyone, I'm about to do a thing!\n",
      "hey hey hey, I'm about to call a function called: say_bye\n",
      "\n",
      "--> bye. <--\n",
      "\n",
      "whoa, did everyone see that thing I just did?! SICK!!\n"
     ]
    }
   ],
   "source": [
    "@verbose\n",
    "def say_bye():\n",
    "    \"\"\"Return 'bye'.\"\"\"\n",
    "    return '--> bye. <--'\n",
    "\n",
    "say_bye()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "Image(url='http://i.giphy.com/piupi6AXoUgTe.gif')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But that shouldn't actually blow your mind. Based on our discussion before, you can probably guess that the decorator notation is just shorthand for: \n",
    "\n",
    "``say_bye = verbose( say_bye )``\n",
    "\n",
    "One place where this shorthand can come in particularly handy is when you need to stack a bunch of decorators. In place of nested decorators like this:\n",
    "\n",
    "```python\n",
    "my_func = do_thing_a( add_numbers( subtract( verify( my_func ))))\n",
    "```\n",
    "\n",
    "We can write this as:\n",
    "\n",
    "```python\n",
    "@do_thing_a\n",
    "@add_numbers\n",
    "@subtract\n",
    "@verify\n",
    "def my_func():\n",
    "    # something useful happens here\n",
    "```\n",
    "\n",
    "Note that the order matters!\n",
    "\n",
    "----\n",
    "\n",
    "\n",
    "Ok, thank you, please come again.\n",
    "\n",
    "\n",
    "# THE END AGAIN\n",
    "\n",
    "----"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ok, final round, I promise. \n",
    "\n",
    "\n",
    "# Appendix\n",
    "\n",
    "\n",
    "This is material that I originally intended to include in this RST (because it's relevant), but ultimately cut for clarity. You can come back and revisit it any time.\n",
    "\n",
    "## Scopes and namespaces\n",
    "\n",
    "Roughly speaking, scope and namespace are the reason you can type some code (like ``variable_1 = 'dog'``) and then transparently use ``variable_1`` later in your code. Sounds obvious, but easy to take for granted!\n",
    "\n",
    "The concepts of scope and namespace in Python are pretty interesting and complex. Some time when you're bored and want to learn some details, have a read of [this nice explainer](http://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html) or the official docs on [the Python Execution Model](https://docs.python.org/2/reference/executionmodel.html). \n",
    "\n",
    "A short way to think about them is the following:\n",
    "\n",
    "- A **namespace** is **a mapping from (variable) names to values**; think about it like a Python dictionary, where our code can look up the keys (the variable names) and then use the corresponding values. You will generally have many namespaces in your code, they are usually nested (sort of like an onion), and they can even have identical keys (variable names). \n",
    "- The **scope** (at a particular location in the code) **defines in which namespace we look for variables** (dictionary keys) when our code is executing.\n",
    "\n",
    "While this RST isn't explicitly about scope, understanding these concepts will make it easier to read the code later on. Let's look at some examples.\n",
    "\n",
    "There are two built-in functions that can aid in exploring the namespace at various points in your code: `globals()` and `locals()` return a dictionary of the names and values in their respective scope. \n",
    "\n",
    "Since the namespaces in IPython are often huge, let's use IPython's bash magic to call out to a normal Python session to test how ``globals()`` works:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# -c option starts a new interpreter session in a subshell and evaluates the code in quotes. \n",
    "#  here, we just assign the value 3 to the variable x and print the global namespace\n",
    "! python -c 'x=3; print( globals() )'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that there are a bunch of other dunder names that are in the global namespace. In particular, note that `'__name__' = '__main__'` because we ran this code from the command line (a comparison that you've made many times in the past!). And you can see the variable x that we assigned the value of 3. \n",
    "\n",
    "We can also look at the namespace in a more local scope with the `locals()` function. Inside the body of a function, the local namespace is limited to those variables defined within the function. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# this var is defined at the \"outermost\" level of this code block\n",
    "z = 10\n",
    "\n",
    "def printer(x):\n",
    "    \"\"\"Print some things to stdout.\"\"\"\n",
    "    \n",
    "    # create a new var within the scope of this function\n",
    "    animal = 'baboon'\n",
    "    \n",
    "    # ask about the namespace of the inner-most scope, \"local\" scope\n",
    "    print('local namespace: {}\\n'.format(locals()))\n",
    "    \n",
    "    # now, what about this var, which is defined *outside* the function?\n",
    "    print('variable defined *outside* the function: {}'.format(z))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "printer(17)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, you can see that when our scope is 'inside the function', **the namespace is very small**. It's the local variables defined within the function, including the arg we passed the function. \n",
    "\n",
    "But, you can also see that we can still \"see\" the variable `z`, which was defined outside the function. This is because even though `z` doesn't exist in the local namespace, **this is just the \"innermost\" of a series of nested namespaces**. When we failed to find `z` in `locals()`, the interpreter steps \"out\" a layer, and looks for a namespace key (variable name) that's defined outside of the function. If we look through this (and any larger) namespace and still fail to find a key (variable name) for ``z``, **the interpreter will raise a ``NameError``**.\n",
    "\n",
    "While the interpreter will always continue looking in *larger* or *more outer* scopes, it can't do the opposite. Since `y` is created and assigned within the scope of our function, it goes \"out of scope\" as soon as the function returns. Local variables defined within the scope of a function are only accessible from that same scope - inside the function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    # remember that this var was created and assigned only within the function\n",
    "    animal\n",
    "except NameError, e:\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Closures\n",
    "\n",
    "This is all relevant, because part of the mechanism behind a decorator is the concept of a function closure. **A function closure captures the enclosing state (namespace) at the time a non-global function is defined.**\n",
    "\n",
    "To see an example, consider the following code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def outer(x):\n",
    "    def inner():\n",
    "        print x\n",
    "    return inner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We saw earlier, that the variable ``x`` isn't directly accessible outside of the function ``outer()``  because it's created within the scope of that function. But, Python's function closures mean that because ``inner()`` is not defined in the global scope, it keeps track of the surrounding namespace wherein it was defined. We can verify this by inspecting an example object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "o = outer(7)\n",
    "\n",
    "o()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "try: \n",
    "    x\n",
    "except NameError, e:\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print( dir(o) ) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print( o.func_closure ) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And, there in the ``repr`` of the object's ``func_closure`` attribute, we can see there is an ``int`` still stored! This is the value that we passed in during the creation of the function."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Links\n",
    "\n",
    "- [Decorators PEP](https://www.python.org/dev/peps/pep-0318/)\n",
    "- [a big list of decorators (only marginally useful)](https://wiki.python.org/moin/PythonDecorators)\n",
    "- [Simeon Franklin's article](http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/)\n",
    "- [The Code Ship](http://thecodeship.com/patterns/guide-to-python-function-decorators/)\n",
    "- [incredible SO explanation](http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python/1594484#1594484)\n",
    "- [another SO response](http://stackoverflow.com/questions/5929107/python-decorators-with-parameters)\n",
    "\n",
    "*fin*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
